﻿/*
 *  Partially adapted from the Inflector.NET - http://andrewpeters.net/inflectornet/ 
 */

using System;
using System.Text.RegularExpressions;

namespace SBToolkit.Text
{
    /// <summary>
    /// Provides different casing operations.
    /// </summary>
    public static class StringCasing
    {
        /// <summary>
        /// Capitalizes specified word.
        /// </summary>
        /// <param name="word">The word to capitalize.</param>
        /// <returns>Capitalize word.</returns>
        public static string Capitalize(this string word)
        {
            word = word ?? String.Empty;
            return word.Substring(0, 1).ToUpper() + (word.Length > 1 ? word.Substring(1).ToLower() : String.Empty);
        }

        /// <summary>
        /// Uncapitalizes specified word.
        /// </summary>
        /// <param name="word">The word to uncapitalize.</param>
        /// <returns>Uncapitalized word.</returns>
        public static string Uncapitalize(this string word)
        {
            word = word ?? String.Empty;
            return word.Substring(0, 1).ToLower() + word.Substring(1);
        }

        /// <summary>
        /// Titleizes specified word.
        /// </summary>
        /// <param name="word">The word to titleize.</param>
        /// <returns>Titleized word.</returns>
        public static string Titleize(this string word)
        {
            word = word ?? String.Empty;
            return Regex.Replace(word.Underscore().Humanize(), @"\b([a-z])", m => m.Captures[0].Value.ToUpper());
        }

        /// <summary>
        /// Humanizes specified word.
        /// </summary>
        /// <param name="lowercaseAndUnderscoredWord">The word to humanize.</param>
        /// <returns>Humanized word.</returns>
        public static string Humanize(this string lowercaseAndUnderscoredWord)
        {
            lowercaseAndUnderscoredWord = lowercaseAndUnderscoredWord ?? String.Empty;
            return Regex.Replace(lowercaseAndUnderscoredWord, @"_", " ").Capitalize();
        }

        /// <summary>
        /// Pascalizes specified word.
        /// </summary>
        /// <param name="lowercaseAndUnderscoredWord">The word to pascalize.</param>
        /// <returns>Pascalized word.</returns>
        public static string Pascalize(this string lowercaseAndUnderscoredWord)
        {
            lowercaseAndUnderscoredWord = lowercaseAndUnderscoredWord ?? String.Empty;
            return Regex.Replace(lowercaseAndUnderscoredWord, "(?:^|_)(.)", m => m.Groups[1].Value.ToUpper());
        }

        /// <summary>
        /// Camelizes specified word.
        /// </summary>
        /// <param name="lowercaseAndUnderscoredWord">The word to camelize.</param>
        /// <returns>Camelized word.</returns>
        public static string Camelize(this string lowercaseAndUnderscoredWord)
        {
            lowercaseAndUnderscoredWord = lowercaseAndUnderscoredWord ?? String.Empty;
            return lowercaseAndUnderscoredWord.Pascalize().Uncapitalize();
        }

        /// <summary>
        /// Underscores specified word.
        /// </summary>
        /// <param name="pascalCasedWord">The word to underscore.</param>
        /// <returns>Underscored word.</returns>
        public static string Underscore(this string pascalCasedWord)
        {
            pascalCasedWord = pascalCasedWord ?? String.Empty;

            var result = Regex.Replace(pascalCasedWord, @"([A-Z]+)([A-Z][a-z])", "$1_$2");
            result = Regex.Replace(result, @"([a-z\d])([A-Z])", "$1_$2");
            result = Regex.Replace(result, @"[-\s]", "_");

            return result.ToLower();
        }

        /// <summary>
        /// Dasherizes specified word in place of underscores.
        /// </summary>
        /// <param name="word">The word to dasherize.</param>
        /// <returns>Dasherized word.</returns>
        public static string Dasherize(string word)
        {
            word = word ?? String.Empty;
            return word.Replace('_', '-');
        }

        /// <summary>
        /// Ordinalizes specified number.
        /// </summary>
        /// <param name="number">The number to ordinalize.</param>
        /// <returns>Ordinalized number.</returns>
        public static string Ordinalize(string number)
        {
            int n;
            if (!Int32.TryParse(number, out n))
            {
                throw new InvalidCastException("Provided argument is not integer.");
            }

            int nMod100 = n % 100;

            if (nMod100 >= 11 && nMod100 <= 13)
            {
                return number + "th";
            }

            switch (n % 10)
            {
                case 1:
                    return number + "st";
                case 2:
                    return number + "nd";
                case 3:
                    return number + "rd";
                default:
                    return number + "th";
            }
        }
    }
}